package modl

import (
	"bufio"
)

type Schema struct {
	Types       map[uint32]*TypeDefinition
	TypesByName map[string]*TypeDefinition
}

type TypeDefinition struct {
	Name          string
	attributeDefs map[uint32]*AttributeDefinition
}

type AttributeDefinition struct {
	Name             string
	AttributeId      uint32
	NewAttributeDiff func(typeId, attributeId uint32, persistable bool) AttributeDiff
}

type MDO interface {
	Serialize(w *bufio.Writer, isPersistentWrite bool)
	Deserialize(r *bufio.Reader, s *Schema)
}

// const (
// 	FirmwareBankTypeId = 3
// )

// const (
// 	FirmwareBankAttributeId_major = iota
// 	FirmwareBankAttributeId_minor
// 	FirmwareBankAttributeId_sub
// )

// type FirmwareBank struct {
// 	sdoType *TypeDefinition
// 	major   uint8
// 	minor   uint8
// 	sub     uint8
// }

// func (new *FirmwareBank) Diff(old *FirmwareBank) (diff SDODiff) {
// 	if new.major != old.major {
// 		diff.add(Uint8Diff{AttributeDiffBase: AttributeDiffBase{TypeId: FirmwareBankTypeId, AttributeId: FirmwareBankAttributeId_major}, OldValue: old.major, NewValue: new.major})
// 	}
// 	if new.minor != old.minor {
// 		diff.add(Uint8Diff{AttributeDiffBase: AttributeDiffBase{TypeId: FirmwareBankTypeId, AttributeId: FirmwareBankAttributeId_minor}, OldValue: old.minor, NewValue: new.minor})
// 	}
// 	if new.sub != old.sub {
// 		diff.add(Uint8Diff{AttributeDiffBase: AttributeDiffBase{TypeId: FirmwareBankTypeId, AttributeId: FirmwareBankAttributeId_sub}, OldValue: old.sub, NewValue: new.sub})
// 	}
// 	return
// }

// func (f *FirmwareBank) Apply(diff SDODiff) {
// 	for diffIdx, attributeDiff := range diff.differences {
// 		typeId, attributeId := attributeDiff.GetAttributeId()
// 		if typeId != FirmwareBankTypeId {
// 			panic(fmt.Sprintf("Invalid type id: Diff %d in %s", diffIdx, diff))
// 		}
// 		switch attributeId {
// 		case FirmwareBankAttributeId_major:
// 			f.major = attributeDiff.(Uint8Diff).NewValue
// 		case FirmwareBankAttributeId_minor:
// 			f.minor = attributeDiff.(Uint8Diff).NewValue
// 		case FirmwareBankAttributeId_sub:
// 			f.sub = attributeDiff.(Uint8Diff).NewValue
// 		default:
// 			panic(fmt.Sprintf("Invalid attribute id: Diff %d in %s", diffIdx, diff))
// 		}
// 	}
// }

// type MacBasedMoKey struct {
// 	mac [6]byte
// }

// const (
// 	BaseStationTypeId = 4
// )

// const (
// 	BaseStationAttributeId_key = iota
// 	BaseStationAttributeId_mgmtIpAddress
// 	BaseStationAttributeId_bankA
// 	BaseStationAttributeId_bankB
// 	BaseStationAttributeId_customFields
// )

// type BaseStation struct {
// 	sdoType       *TypeDefinition
// 	key           *MacBasedMoKey
// 	mgmtIpAddress *string
// 	bankA         *FirmwareBank
// 	bankB         *FirmwareBank
// 	customFields  []*string
// }

// func (new *BaseStation) Diff(old *BaseStation) (diff SDODiff) {
// 	if new.mgmtIpAddress != old.mgmtIpAddress {
// 		diff.add(StringDiff{AttributeDiffBase: AttributeDiffBase{AttributeId: BaseStationAttributeId_mgmtIpAddress}, OldValue: old.mgmtIpAddress, NewValue: new.mgmtIpAddress})
// 	}
// 	if bankADiff := new.bankA.Diff(&old.bankA); len(bankADiff.differences) != 0 {
// 		diff.add(StructDiff{AttributeDiffBase: AttributeDiffBase{AttributeId: BaseStationAttributeId_bankA}, Diff: bankADiff})
// 	}
// 	if bankBDiff := new.bankB.Diff(&old.bankB); len(bankBDiff.differences) != 0 {
// 		diff.add(StructDiff{AttributeDiffBase: AttributeDiffBase{AttributeId: BaseStationAttributeId_bankB}, Diff: bankBDiff})
// 	}
// 	for idx, newVal := range new.customFields {
// 		if idx >= len(old.customFields) {
// 			diff.add(SliceDiff{AttributeDiffBase: AttributeDiffBase{AttributeId: BaseStationAttributeId_customFields}, Idx: idx, Oper: DiffOper_add, ActualDiff: StringDiff{NewValue: newVal}})
// 			continue
// 		}
// 		if oldVal := old.customFields[idx]; oldVal != newVal {
// 			diff.add(SliceDiff{AttributeDiffBase: AttributeDiffBase{AttributeId: BaseStationAttributeId_customFields}, Idx: idx, Oper: DiffOper_modify, ActualDiff: StringDiff{OldValue: oldVal, NewValue: newVal}})
// 		}
// 	}
// 	if len(old.customFields) > len(new.customFields) {
// 		diff.add(SliceDiff{AttributeDiffBase: AttributeDiffBase{AttributeId: BaseStationAttributeId_customFields}, Idx: len(new.customFields), Oper: DiffOper_truncate})
// 	}
// 	return
// }

// func (b *BaseStation) Apply(diff SDODiff) {
// 	for diffIdx, attributeDiff := range diff.differences {
// 		typeId, attributeId := attributeDiff.GetAttributeId()
// 		if typeId != BaseStationTypeId {
// 			panic(fmt.Sprintf("Invalid type id: Diff %d in %s", diffIdx, diff))
// 		}
// 		switch attributeId {

// 		case BaseStationAttributeId_mgmtIpAddress:
// 			b.mgmtIpAddress = attributeDiff.(StringDiff).NewValue

// 		case BaseStationAttributeId_bankA:
// 			b.bankA.Apply(attributeDiff.(StructDiff).Diff)

// 		case BaseStationAttributeId_bankB:
// 			b.bankB.Apply(attributeDiff.(StructDiff).Diff)

// 		case BaseStationAttributeId_customFields:
// 			sliceDiff := attributeDiff.(SliceDiff)
// 			switch sliceDiff.Oper {

// 			case DiffOper_add:
// 				if len(b.customFields) != sliceDiff.Idx {
// 					panic(fmt.Sprintf("Invalid attempt to add to customFields: Diff %d in\n%s\nExisting Object: %s", diffIdx, diff, *b))
// 				}
// 				b.customFields = append(b.customFields, sliceDiff.ActualDiff.(StringDiff).NewValue)

// 			case DiffOper_modify:
// 				if len(b.customFields) <= sliceDiff.Idx {
// 					panic(fmt.Sprintf("Invalid attempt to modify customFields: Diff %d in\n%s\nExisting Object: %s", diffIdx, diff, *b))
// 				}
// 				b.customFields[sliceDiff.Idx] = sliceDiff.ActualDiff.(StringDiff).NewValue

// 			case DiffOper_truncate:
// 				b.customFields = b.customFields[0:sliceDiff.Idx]

// 			default:
// 				panic(fmt.Sprintf("Invalid diff operation: Diff %d in %s", diffIdx, diff))
// 			}

// 		default:
// 			panic(fmt.Sprintf("Invalid attribute id: Diff %d in %s", diffIdx, diff))
// 		}
// 	}
// }

// func (b *BaseStation) Key() MoKey {
// 	return b.key
// }
